package com.xyq.common.sucurity.service;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.xyq.common.core.constants.CacheConstants;
import com.xyq.common.core.constants.HttpConstants;
import com.xyq.common.core.constants.JwtConstants;
import com.xyq.common.core.domain.Result;
import com.xyq.common.redis.service.RedisService;
import com.xyq.common.core.domain.LoginUser;
import com.xyq.common.core.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class TokenService {
    @Autowired
    private RedisService redisService ;

    public String createToken(Long userId , String secret , Integer identity , String nickName , String headImage ) {
       // 1. 创建token
        Map<String,Object> claim = new HashMap<>();
       // 2. UUID 创建一的随机数,也是在token里面
        String userKey = UUID.fastUUID().toString() ;
         claim.put(JwtConstants.LOGIN_USER_ID , userId) ;
         claim.put(JwtConstants.LOGIN_USER_KEY,userKey) ;
         //3. 创建token
         String token =  JwtUtils.createToken(claim , secret) ;

         // 在redis里保存token信息 ;
        //4. 创建LoginUser对象 ,这个对象存储当前用户是普通用户还是管理员
        LoginUser loginUser = new LoginUser() ;
        loginUser.setIdentity(identity);
        loginUser.setNickName(nickName);

        // 存储用户头像
        loginUser.setHeadImage(headImage);

        //5. redis存储Token缓存 , 同时指定 过期时间
        //6. 存储的key是 loginken:  + userKey 用户的唯一标识:就是上面UUID创建的userKey
        String tokenKey = CacheConstants.LOGIN_TOKEN_KEY + userKey ;
        // 7. value就是
        //8. redis里保存 token信息
        redisService.setCacheObject(tokenKey,loginUser,CacheConstants.EXPIRATION, TimeUnit.MINUTES);

        // 9.最后返回的就是 创建的token
        return token ;
    }

    // 1.延长token的有效时间,就是延长redis当中存储tokenKey信息的 有效时间
       // 2.需要获取tokenKey  和 secret 这样才能设置 redis里的数据
    public void extendToken(Claims claims){
        String userKey = getUserKey( claims) ;
        if(userKey == null) return; ;

        //3.从redis里获取 token 有效时间
        String tokenKey = getTokenKey(userKey);  // 创建token设置的是 720分钟,所以获取也用 分钟
        Long time = redisService.getExpires(tokenKey,TimeUnit.MINUTES);
        boolean flg = false ;
        // 当token有效时间小于 180分钟 ,  延长180分钟, 时间单位是分钟,
        if(time != null && time < CacheConstants.EXTEND_TIME) {   // 延长时间也加到 常量类里
           flg =  redisService.expire(tokenKey , CacheConstants.EXTEND_TIME , TimeUnit.MINUTES);
        }
        log.error("是否延长成功"+flg);
    }
    public String getUserKey(Claims claims){

        String userKey =JwtUtils.getUserKey(claims);
        return userKey ;
    }

    private String getTokenKey(String token) {
        return CacheConstants.LOGIN_TOKEN_KEY + token;
    }


    public LoginUser getLoginUser(String token ,String secret) {
         String userKey = getUserKey(getClaims(token , secret)) ;
          if(userKey == null) return  null ;
          return redisService.getCacheObject(getTokenKey(userKey) , LoginUser.class) ;
    }

    public boolean deleteLoginUser(String token, String secret) {
        // 验证 登录信息
        String userKey = getUserKey(getClaims(token ,secret)) ;
        if(userKey == null) return  false ;
       return   redisService.deleteObject(getTokenKey(userKey));
    }

    public Claims getClaims(String token , String secret){
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        // 从请求中的token中获取唯一标识信息,这样才能从 redis里获取过期信息
        Claims claims;
        try {                                 //从把token 反序列化,解析回 Key,value的形式 ,拿回token中的信息
            claims = JwtUtils.parseToken(token, secret); //获取令牌中信息 解析payload中信息
            if (claims == null) {
                log.error("无法从token中获取数据{}",token);
                return null ;
            }
        } catch (Exception e) {
            log.error("从token中获取数据发生异常:{}{  }",e,token);
            return null;
        }
        return claims ;
    }

   // 获取用户id

    public Long getUserId(Claims claims) {
        return Long.valueOf(getUserKeyId(claims));
    }
    // 解析token获取 userid
    private String getUserKeyId(Claims claims){
        String userKey =JwtUtils.getUserId(claims);
        return userKey ;
    }
    // 更新缓存里的数据
    public void refreshLoginUser(String nickName, String headImage, String userKey) {
        // 把缓存里的存储的数据取出来
        String tokenKey = getTokenKey(userKey);
        LoginUser loginUser = redisService.getCacheObject(tokenKey, LoginUser.class);
        loginUser.setNickName(nickName);
        loginUser.setHeadImage(headImage);
        // 更新 缓存里的数据
        redisService.setCacheObject(tokenKey , loginUser);
    }
}
